import operator

from graphics import *
from random import *


#
# 2019-10-4
# 类 COLOR是用来存放颜色的
# 类 Puzzle8是八数码的主要实现功能类
#   以下对几个方法给予说明
#   初始化类，包含类的成员属性设置
#   __init__(self, width, height, title='八数码--董尧')
#   对八数码进行绘制
#   drawPuzzle8(self)
#   获取矩形框的文本框
#   getValue(self, rectangle)
#   设置矩形框的文本框
#   setValue(self, rectangle, value)
#   初始化面板
#   __initPlane__(self, width, height, gap)
#   动作指令
#   __puzzleAction(self, width, height)
#   获取随机值
#   __getRandomNumber__(self)
#   通过矩形框获取文本对象
#   __getTextFromRectangle(self, rectangle)
#   检查两个矩形框的相邻性
#   __checkClosest(self, firstRectangle, secondRectangle, width, height)


class COLOR:
    GRAY = color_rgb(237, 234, 232)
    GREEN = color_rgb(9, 187, 7)
    BLUE = color_rgb(62, 88, 201)


class Puzzle8:
    def __init__(self, width, height, title='八数码--董尧'):
        self.puzzle8num = [x for x in range(1, 9)]
        self.targetPuzzle8num = [x for x in range(1, 9)]
        self.title = title
        self.width = width
        self.height = height
        # 第一个矩形框对象
        self.__firstRectangle = None
        # 第一个是否被选择标志
        self.__choose = False
        # 矩形框对象
        self.rectangles = []
        # 文本对象
        self.texts = []
        # 矩形框对象
        self.targetRectangles = []
        # 文本对象
        self.targetTexts = []
        self.timer = 0
        self.tips = None
        self.winTips = None
        self.win = GraphWin(title, self.width, self.height)

    def drawPuzzle8(self):
        # 设置上下左右边距
        gap = 50
        # 计算宽和高
        __height = (self.height - 2 * gap) / 3
        __width = (self.width - 500 - 2 * gap) / 3
        # 初始化面板
        self.__initLeftPlane__(__width, __height, gap)
        self.__initRightPlane__(__width, __height, gap)
        # 初始化界面提示
        self.__showMessage(__width, __height, gap)
        # 动作方法
        self.__puzzleAction(__width, __height)

    # 设置矩形框内的文本值
    def setValue(self, rectangle, value):
        return self.__getTextFromRectangle(rectangle).setText(value)

    # 获取矩形框内的文本值
    def getValue(self, rectangle):
        return self.__getTextFromRectangle(rectangle).getText()

    # 初始化面板
    def __initPlane__(self, width, height, gap, rectangles, texts, randoms, widthOffset=0):
        for row in (0, 1, 2):
            for column in (0, 1, 2):
                # 计算左上角和右下角的坐标
                P1 = Point(row * width + gap + widthOffset, column * height + gap)
                P2 = Point((row + 1) * width + gap + widthOffset, (column + 1) * height + gap)
                # 实例化一个矩形框并且给矩形框填充颜色
                rect = Rectangle(P1, P2)
                rect.setFill(COLOR.GRAY)
                # 实例化文本对象，并且设置填充颜色和字体大小
                if column * row == 4:
                    text = Text(rect.getCenter(), '')
                else:
                    text = Text(rect.getCenter(), self.__getRandomNumber__(randoms))
                text.setFill(COLOR.BLUE)
                text.setSize(22)
                # 绘制矩形框
                rect.draw(self.win)
                rectangles.append(rect)
                # 绘制文本框
                text.draw(self.win)
                texts.append(text)

    # 初始化左面板
    def __initLeftPlane__(self, width, height, gap):
        self.__initPlane__(width, height, gap, self.rectangles, self.texts, self.puzzle8num)

    # 初始化右面板
    def __initRightPlane__(self, width, height, gap):
        self.__initPlane__(width, height, gap, self.targetRectangles, self.targetTexts, self.targetPuzzle8num, 500)

    # 展示整个界面的提示信息
    def __showMessage(self, width, height, gap):
        operateLabel = Text(Point(self.width / 2 / 2, gap / 2), '操作区')
        operateLabel.setSize(22)
        operateLabel.draw(self.win)

        targetLabel = Text(Point(self.width / 2 / 2 * 3, gap / 2), '目标')
        targetLabel.setSize(22)
        targetLabel.draw(self.win)

        tip = Text(Point(gap * 2, self.height - gap + gap / 2), '操作次数：')
        tip.setSize(22)
        tip.draw(self.win)

        self.tips = Text(Point(gap + width, self.height - gap + gap / 2), self.timer)
        self.tips.setSize(22)
        self.tips.draw(self.win)

        self.winTips = Text(Point(self.width - gap, self.height - gap + gap / 2), '成功')
        self.winTips.setSize(22)

    # 动作指令
    def __puzzleAction(self, width, height):
        while True:
            # 获取对象ID
            ids = self.win.find_closest(self.win.getMouse().getX(), self.win.getMouse().getY())
            # 提取左边的元素
            leftItem = self.win.items[:18]
            for thisItem in leftItem:
                if thisItem.id == ids[0]:
                    # 判断点击区域是否为矩形框
                    if type(thisItem) == Rectangle:
                        # 获取对应的矩形区域内的文本对象
                        text = self.__getTextFromRectangle(thisItem)
                        # 判断文本对象是否为空并且选择是否为假
                        # 说明
                        if (text.getText() == '' or text.getText() is None) and self.__choose is False:
                            self.__firstRectangle = thisItem
                            thisItem.setFill(COLOR.GREEN)
                            self.__choose = True
                        elif self.__choose and self.__checkClosest(self.__firstRectangle, thisItem, width, height):
                            self.__firstRectangle.setFill(COLOR.GRAY)
                            self.setValue(self.__firstRectangle, self.getValue(thisItem))
                            self.setValue(thisItem, '')
                            self.timer += 1
                            self.__choose = False
                            # 计数显示
                            self.tips.setText(self.timer)
            self.__checkWin()
        self.win.close()

    # 检查是否成功
    def __checkWin(self):
        if operator.eq([x.getText() for x in self.texts], [x.getText() for x in self.targetTexts]):
            self.winTips.draw(self.win)

    # 获取随机值
    def __getRandomNumber__(self, randoms):
        if randoms.__len__() > 0:
            randomNum = choice(randoms)
            randoms.remove(randomNum)
            return randomNum

    # 通过矩形框获取文本对象
    def __getTextFromRectangle(self, rectangle):
        # 定义计数器
        timers = 0
        for item in self.rectangles:
            # 判断
            if item == rectangle:
                return self.texts[timers]
            timers += 1

    # 检查两个矩形框的相邻性
    def __checkClosest(self, firstRectangle, secondRectangle, width, height):
        # 获取两个矩形框的中心坐标
        P1 = firstRectangle.getCenter()
        P2 = secondRectangle.getCenter()
        # 如果两个中心坐标X差值为零并且两个中心坐标的Y值为零
        # 或者两个中心坐标Y差值为零并且两个中心坐标的X值为零
        # 那么说明两个矩形相邻
        if abs(int(abs(P1.getX() - P2.getX()) - width)) == 0 and P1.getY() == P2.getY():
            return True
        elif P1.getX() == P2.getX() and abs(int(abs(P1.getY() - P2.getY()) - height)) == 0:
            return True
        else:
            return False
